# ============================================================================
# 文件路径: src/cache.nim
# 文件用途: Redis 缓存管理和速率限制功能
#
# 功能说明:
# 1. 管理 Redis 连接池，提供高效的数据库连接复用
# 2. 实现 API 速率限制 (每分钟最多 60 个请求)
# 3. 提供速率限制检查和计数器管理
# 4. 集成 HTTP 响应头设置，符合 REST API 标准
# ============================================================================

# 导入标准库
import std/[
  json,         # JSON 数据处理
  options       # 可选类型处理
]

# 导入 Web 框架和 Redis 客户端
import
  mummy, mummy_utils,    # HTTP 请求处理
  ready                  # Redis 客户端库

# ============================================================================
# Redis 连接池配置
# 使用连接池可以提高性能，避免频繁创建和销毁连接
# 池大小设为 3，适合中等负载的应用
# ============================================================================
let cachePool* = newRedisPool(3)


# ============================================================================
# 速率限制核心函数
# ============================================================================

proc rateLimitIncrement(ip: string): int =
  ## 原子性地增加 IP 地址的请求计数器
  ## 
  ## 参数:
  ##   ip: 客户端 IP 地址
  ## 返回:
  ##   当前计数值
  ##
  ## 实现细节:
  ## - 使用 Redis INCR 命令确保原子性操作
  ## - 为新 IP 自动设置 60 秒过期时间
  ## - 键格式: "rate_limit:IP地址"
  ## - Redis 不可用时返回 1 (允许请求通过)
  try:
    cachePool.withConnection conn:
      # 使用 INCR 原子性地增加计数器，如果键不存在会自动创建并设为 1
      let count = conn.command("INCR", "rate_limit:" & ip)
      result = count.to(int)

      # 如果这是第一个请求 (计数为 1)，设置过期时间为 60 秒
      # 这样计数器会在 1 分钟后自动清零
      if result == 1:
        discard conn.command("EXPIRE", "rate_limit:" & ip, "60")
  except CatchableError:
    # Redis 不可用时，返回 1 允许请求通过
    result = 1

proc rateLimitCheck(ip: string): bool =
  ## 检查 IP 地址是否超过速率限制
  ## 
  ## 参数:
  ##   ip: 客户端 IP 地址
  ## 返回:
  ##   true 表示超过限制，false 表示在允许范围内
  ##
  ## 限制规则:
  ## - 每分钟最多 60 个请求
  ## - 超过限制的请求将被拒绝并返回 429 状态码
  ## - Redis 不可用时不限制 (返回 false)
  try:
    cachePool.withConnection conn:
      let count = conn.command("GET", "rate_limit:" & ip)
      let countOpt = count.to(Option[int])
      if countOpt.isSome:
        return countOpt.get > 60  # 超过 60 个请求视为超限
      return false  # 没有记录表示未超限
  except CatchableError:
    # Redis 不可用时不限制请求
    return false

# ============================================================================
# 速率限制模板 - 集成到 HTTP 处理器中
# ============================================================================

template ratelimitHeaders*(request: Request, headers: var HttpHeaders) =
  ## 速率限制检查和 HTTP 头设置模板
  ## 
  ## 功能:
  ## 1. 自动检查客户端 IP 的请求频率
  ## 2. 设置标准的速率限制 HTTP 响应头
  ## 3. 超限时自动返回 429 状态码并终止请求处理
  ## 4. 正常情况下更新剩余请求数量头
  ##
  ## HTTP 响应头说明:
  ## - X-RateLimit-Limit: 每分钟允许的最大请求数 (60)
  ## - X-RateLimit-Remaining: 当前时间窗口内剩余的请求数
  ##
  ## 使用方式:
  ## 在每个 API 处理器开头调用此模板即可自动应用速率限制
  
  let ip = request.ip()  # 获取客户端真实 IP 地址
  let currentCount = rateLimitIncrement(ip)  # 增加计数并获取当前值
  
  # 检查是否超过限制
  if rateLimitCheck(ip):
    # 超限处理：设置响应头并返回 429 错误
    headers["X-RateLimit-Limit"] = "60"
    headers["X-RateLimit-Remaining"] = "0"
    request.respond(429, headers, $(%*{"error": "Rate limit exceeded. Maximum 60 requests per minute."}))
    return  # 终止当前请求处理

  # 正常情况：设置速率限制信息头
  headers["X-RateLimit-Limit"] = "60"
  headers["X-RateLimit-Remaining"] = $(60 - currentCount)